package com.jianggujin.redis.component;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.MouseListener;
import java.util.List;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;

import lombok.Getter;
import lombok.Setter;

/**
 * 可编辑表格
 * 
 * @author jianggujin
 *
 */
public class JEditorTable extends JScrollPane {

    private TableModel model;
    private JTable table;
    private JTableHeader tableHeader;
    private boolean showLineNumbers = true;
    private boolean[] columnEditable = {};

    public JEditorTable(String[] headers) {
        this(true, headers);
    }

    public JEditorTable() {
        this(true, null);
    }

    public JEditorTable(boolean showLineNumbers) {
        this(showLineNumbers, null);
    }

    public JEditorTable(boolean showLineNumbers, String[] headers) {
        this.showLineNumbers = showLineNumbers;
        this.model = new TableModel();
        this.table = new JTable(this.model);
        this.tableHeader = this.table.getTableHeader();
        // 不可整列移动
        this.tableHeader.setReorderingAllowed(false);
        this.table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        this.tableHeader.setPreferredSize(new Dimension(this.tableHeader.getWidth(), 30));
        ((JLabel) this.tableHeader.getDefaultRenderer()).setHorizontalAlignment(JLabel.CENTER);
        // 添加RowId
        this.model.addColumn("");
        // 添加用户列
        if (headers != null) {
            for (int i = 0; i < headers.length; i++) {
                this.model.addColumn(headers[i]);
            }
        }
        resizeRowIdWidth();

        setRowHeight(30);
        TableCellListener.addTableCellListener(table, new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                handleCellChanged((TableCellListener) e.getSource());
            }
        });
        this.setViewportView(table);
    }

    private void handleCellChanged(TableCellListener tcl) {
//        System.out.printf("cell changed%n");
//        System.out.println("Row   : " + tcl.getRow());
//        System.out.println("Column: " + tcl.getColumn());
//        System.out.println("Old   : " + tcl.getOldValue());
//        System.out.println("New   : " + tcl.getNewValue());
        this.model.setRowUpdated(tcl.getRow());
    }

    /**
     * 添加列
     * 
     * @param name
     */
    public void addColumn(String columnName) {
        this.model.addColumn(columnName);
        resizeRowIdWidth();
    }

    public void setColumnEditable(int columnIndex, boolean editable) {
        this.columnEditable[fitColumnIndex(columnIndex)] = editable;
    }

    public boolean isColumnEditable(int columnIndex) {
        return this.columnEditable[fitColumnIndex(columnIndex)];
    }

    private void resizeRowIdWidth() {
        int width = showLineNumbers ? 50 : 0;
        TableColumn column = this.tableHeader.getColumnModel().getColumn(0);
        column.setPreferredWidth(width);
        column.setMinWidth(width);
        column.setMaxWidth(width);

    }

    /**
     * 设置行高
     * 
     * @param rowHeight
     */
    public void setRowHeight(int rowHeight) {
        this.table.setRowHeight(rowHeight);
    }

    /**
     * 设置行高
     * 
     * @param row
     * @param rowHeight
     */
    public void setRowHeight(int row, int rowHeight) {
        this.table.setRowHeight(row, rowHeight);
    }

    private int fitColumnIndex(int columnIndex) {
        if (columnIndex < 0) {
            throw new IllegalArgumentException("columnIndex must more than 0.");
        }
        return columnIndex + 1;
    }

    /**
     * 设置列宽
     * 
     * @param columnIndex
     * @param width
     */
    public void setColumnWidth(int columnIndex, int width) {
        TableColumn column = this.tableHeader.getColumnModel().getColumn(fitColumnIndex(columnIndex));
        column.setPreferredWidth(width);
        column.setMinWidth(width);
        column.setMaxWidth(width);
    }

    /**
     * 设置最小列宽
     * 
     * @param columnIndex
     * @param width
     */
    public void setColumnMinWidth(int columnIndex, int width) {
        TableColumn column = this.tableHeader.getColumnModel().getColumn(fitColumnIndex(columnIndex));
        column.setMinWidth(width);
    }

    /**
     * 设置最大列宽
     * 
     * @param columnIndex
     * @param width
     */
    public void setColumnMaxWidth(int columnIndex, int width) {
        TableColumn column = this.tableHeader.getColumnModel().getColumn(fitColumnIndex(columnIndex));
        column.setMaxWidth(width);
    }

    /**
     * 获得行数
     * 
     * @return
     */
    public int getRowCount() {
        return this.table.getRowCount();
    }

    /**
     * 获得列数
     * 
     * @return
     */
    public int getColumnCount() {
        return this.table.getColumnCount() - 1;
    }

    /**
     * 添加行
     * 
     * @param rowData
     */
    public void addRow(Object[] rowData) {
        if (rowData == null) {
            return;
        }
        Vector<Object> v = new Vector<Object>(rowData.length + 1);
        v.addElement(new RowId(getRowCount() + 1));
        for (Object o : rowData) {
            v.addElement(o);
        }
        this.model.addRow(v);
    }

    /**
     * 添加新行
     * 
     */
    public void addNewRow(Object[] rowData) {
        if (rowData == null) {
            rowData = new Object[0];
        }
        Vector<Object> v = new Vector<Object>(rowData.length + 1);
        RowId rowId = new RowId(getRowCount() + 1);
        rowId.setAdd(true);
        v.addElement(rowId);
        for (Object o : rowData) {
            v.addElement(o);
        }
        this.model.addRow(rowData);
    }

    /**
     * 移除行
     * 
     * @param row
     */
    public void removeRow(int row) {
        this.model.removeRow(row);
        int count = getRowCount();
        for (int i = row; i < count; i++) {
            setValueAt(i + 1, row, 0);
            RowId rowId = (RowId) this.table.getValueAt(row, 0);
            rowId.setRowId(i + 1);
            this.table.setValueAt(rowId, row, 0);
        }
    }

    /**
     * 移除全部行
     */
    public void removeAllRow() {
        int count = getRowCount();
        for (int i = 0; i < count; i++) {
            this.model.removeRow(0);
        }
    }

    /**
     * 设置指定位置的值
     * 
     * @param value
     * @param row
     * @param column
     */
    public void setValueAt(Object value, int row, int column) {
        this.table.setValueAt(value, row, fitColumnIndex(column));
    }

    /**
     * 获得指定位置的值
     * 
     * @param value
     * @param row
     * @param column
     */
    public Object getValueAt(int row, int column) {
        return this.table.getValueAt(row, fitColumnIndex(column));
    }

    /**
     * 设置选择模式
     * 
     * @param selectionMode
     * @see JList#setSelectionMode
     * @beaninfo description: The selection mode used by the row and column
     *           selection models. enum: SINGLE_SELECTION
     *           ListSelectionModel.SINGLE_SELECTION SINGLE_INTERVAL_SELECTION
     *           ListSelectionModel.SINGLE_INTERVAL_SELECTION
     *           MULTIPLE_INTERVAL_SELECTION
     *           ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
     */
    public void setSelectionMode(int selectionMode) {
        this.table.setSelectionMode(selectionMode);
    }

    /**
     * 获得选择的行，没有选择则返回-1
     * 
     * @return
     */
    public int getSelectedRow() {
        return this.table.getSelectedRow();
    }

    public void setRowSelectionAllowed(boolean rowSelectionAllowed) {
        this.table.setRowSelectionAllowed(rowSelectionAllowed);
    }

    class TableModel extends DefaultTableModel {
        private List<Vector<?>> removeRows = new Vector<>();

        @Override
        public synchronized void addColumn(Object columnName) {
            boolean[] columnEditableTemp = new boolean[columnEditable.length + 1];
            System.arraycopy(columnEditable, 0, columnEditableTemp, 0, columnEditable.length);
            columnEditable = columnEditableTemp;
            super.addColumn(columnName);
        }

        @Override
        public void removeRow(int row) {
            removeRows.add((Vector<?>) dataVector.elementAt(row));
            super.removeRow(row);
        }

        /**
         * 标记某行为修改状态
         * 
         * @param row
         */
        public void setRowUpdated(int row) {
            Vector<?> rowVector = (Vector<?>) dataVector.elementAt(row);
            RowId rowId = (RowId) rowVector.elementAt(0);
            rowId.setUpdate(true);
            fireTableCellUpdated(row, 0);
        }

        /**
         * 标记某行为添加状态
         * 
         * @param row
         */
        public void clearRowFlag(int row) {
            Vector<?> rowVector = (Vector<?>) dataVector.elementAt(row);
            RowId rowId = (RowId) rowVector.elementAt(0);
            rowId.setUpdate(false);
            rowId.setAdd(false);
            fireTableCellUpdated(row, 0);
        }

        public void saveChanges() {
            removeRows.clear();
            fireTableDataChanged();
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return columnEditable[column];
        }
    }

    @Setter
    @Getter
    static class RowId {
        private int rowId;
        private boolean update;
        private boolean add;

        public RowId(int rowId) {
            this.rowId = rowId;
        }

        @Override
        public String toString() {
            return String.valueOf(rowId);
        }
    }

    public void addTableMouseListener(MouseListener l) {
        this.table.addMouseListener(l);
    }
}
